#include "ask_decode.h"

#include <stdio.h>
#include <stdlib.h>

#define BUF_STEP_SIZE 1024

#define STATE_SEEK_SYNC

void expand_ask_decoder_buffer(struct ask_decoder *dec);

void init_ask_decoder(struct ask_decoder *dec,int samplerate)
{
	dec->decode_buffer_size=BUF_STEP_SIZE;
	dec->decoded_bytes=malloc(dec->decode_buffer_size);
	if(!dec->decoded_bytes) { fprintf(stderr,"Out of memory\n"); exit(10); }

	dec->num_decoded_bits=0;
	dec->samplerate=samplerate;

	dec->state=STATE_NO_SYNC;

	dec->lastsample=0;
	dec->samplecount=0;
	dec->sum=0;
	dec->lastzero=0;
}

void destroy_ask_decoder(struct ask_decoder *dec)
{
	free(dec->decoded_bytes);
}

static inline int pos(int val) { return val>=0?1:0; }

void provide_ask_input(struct ask_decoder *dec,int16_t *samples,int num_samples)
{
	int min_interval=2*dec->samplerate/(1024*2*3);
	int max_interval=4*dec->samplerate/(1024*2*3);

	for(int i=0;i<num_samples;i++)
	{
		int sample=samples[i];
		int zero=0,interval,valid,integral;

		dec->sum+=sample;
		dec->samplecount++;

		sample-=dec->sum/dec->samplecount; // adjust zero level

		if(pos(sample)!=pos(dec->lastsample)) // zero crossing
		{
			zero=1;
			interval=dec->samplecount-dec->lastzero;
			valid=interval>=min_interval&&interval<=max_interval;
			integral=abs(dec->currintegral);
			dec->currintegral=0;
			dec->lastzero=dec->samplecount;
		}
		dec->lastsample=sample;
		dec->currintegral+=sample;

		int threshold=(dec->zerointegral+dec->oneintegral)/2;

		if(zero)
		{
			switch(dec->state)
			{
				case STATE_NO_SYNC:
					dec->state=STATE_FIRST_BIT;
				break;

				case STATE_FIRST_BIT:
					if(!valid) { dec->state=STATE_NO_SYNC; break; }
					dec->firstintegral=integral;
					dec->state=STATE_FIRST_SKIP;
				break;

				case STATE_FIRST_SKIP:
					if(!valid) { dec->state=STATE_NO_SYNC; break; }
					dec->state=STATE_SECOND_BIT;
				break;

				case STATE_SECOND_BIT:
					if(!valid) { dec->state=STATE_NO_SYNC; break; }

					//threshold=(dec->firstbit+integral)/2;
					dec->pulsecount=0;

					if(dec->firstintegral>integral)
					{
						dec->state=STATE_SKIP_AND_EXPECT_1;
						dec->zerointegral=dec->firstintegral;
						dec->oneintegral=integral;
					}
					else
					{
						dec->state=STATE_SKIP_AND_EXPECT_0;
						dec->zerointegral=integral;
						dec->oneintegral=dec->firstintegral;
					}
				break;

				case STATE_SKIP_AND_EXPECT_0:
					if(!valid) { dec->state=STATE_NO_SYNC; break; }
					dec->state=STATE_EXPECT_0;
				break;

				case STATE_EXPECT_0:
					if(!valid) { dec->state=STATE_NO_SYNC; break; }
					if(integral>threshold) { dec->state=STATE_NO_SYNC; break; }
					dec->zerointegral=integral;
					dec->state=STATE_SKIP_AND_EXPECT_1;
				break;

				case STATE_SKIP_AND_EXPECT_1:
					if(!valid) { dec->state=STATE_NO_SYNC; break; }
					dec->state=STATE_EXPECT_1;
				break;

				case STATE_EXPECT_1:
					if(!valid) { dec->state=STATE_NO_SYNC; break; }
					dec->pulsecount++;
					if(integral<threshold)
					{
						if(dec->pulsecount>=10)
						{
							dec->zerointegral=integral;
							dec->state=STATE_SKIP_AND_PAD_1;
						}
						else
						{
							dec->state=STATE_NO_SYNC;
						}
						break;
					}

					dec->oneintegral=integral;
					dec->state=STATE_SKIP_AND_EXPECT_0;
				break;

				case STATE_SKIP_AND_PAD_1:
					if(!valid) { dec->state=STATE_LOST_SYNC; break; }
					dec->state=STATE_PAD_1;
				break;

				case STATE_PAD_1:
					if(!valid) { dec->state=STATE_LOST_SYNC; break; }
					if(integral>threshold) { dec->state=STATE_LOST_SYNC; break; }
					dec->zerointegral=integral;
					dec->state=STATE_SKIP_AND_PAD_2;
				break;

				case STATE_SKIP_AND_PAD_2:
					if(!valid) { dec->state=STATE_LOST_SYNC; break; }
					dec->state=STATE_PAD_2;
				break;

				case STATE_PAD_2:
					if(!valid) { dec->state=STATE_LOST_SYNC; break; }
					if(integral>threshold) { dec->state=STATE_LOST_SYNC; break; }
					dec->zerointegral=integral;
					dec->state=STATE_SKIP_AND_READ_BIT;
				break;

				case STATE_SKIP_AND_READ_BIT:
					if(!valid) { dec->state=STATE_LOST_SYNC; break; }
					dec->state=STATE_READ_BIT;
				break;

				case STATE_READ_BIT:
					if(!valid) { dec->state=STATE_LOST_SYNC; break; }

					int byteoffset=dec->num_decoded_bits/8;
					int bitoffset=dec->num_decoded_bits%8;

					if(byteoffset>=dec->decode_buffer_size) expand_ask_decoder_buffer(dec);

//					if(integral>threshold) dec->decoded_bytes[byteoffset]|=0x80>>bitoffset;
//					else dec->decoded_bytes[byteoffset]&=~(0x80>>bitoffset);
					if(integral>threshold)
					{
						dec->decoded_bytes[byteoffset]|=1<<bitoffset;
						dec->oneintegral=integral;
					}
					else
					{
						dec->decoded_bytes[byteoffset]&=~(1<<bitoffset);
						dec->zerointegral=integral;
					}

					dec->num_decoded_bits++;

					dec->state=STATE_SKIP_AND_READ_BIT;
				break;

				case STATE_LOST_SYNC:
				break;
			}
		}
	}
}

void expand_ask_decoder_buffer(struct ask_decoder *dec)
{
	int newsize=dec->decode_buffer_size+BUF_STEP_SIZE;
	u_int8_t *newbuf=realloc(dec->decoded_bytes,newsize);
	if(!newbuf) { fprintf(stderr,"Out of memory\n"); exit(10); }

	dec->decoded_bytes=newbuf;
	dec->decode_buffer_size=newsize;
}

u_int8_t *ask_data_bytes(struct ask_decoder *dec)
{
	return dec->decoded_bytes;
}

int ask_data_length(struct ask_decoder *dec)
{
	return (dec->num_decoded_bits+7)/8;
}

int is_ask_sync_found(struct ask_decoder *dec)
{
	return dec->state==STATE_SKIP_AND_READ_BIT||dec->state==STATE_READ_BIT||dec->state==STATE_LOST_SYNC;
}

int is_ask_sync_lost(struct ask_decoder *dec)
{
	return dec->state==STATE_LOST_SYNC;
}

